#测试正则表达式相关内容

import re
# re 为 python3 提供的 正则表达式模块

#正则表达式概念说明
def RegularDefine():
   
#正则表达式概念：
#  正则表达式是由普通字符（例如字符a到z）以及特殊字符（例如限定符，元字符）
#  组成的字符串描述句式。该句式描述了一个字符串的格式，匹配函数会按照该格式
#  搜索目标字符串，然后给出目标字符串中与该格式匹配的一个或多个小字符串。
#
#例如：
#  表达式   ^[0-9]+abc$  
#  ^ 为匹配输入字符串的开始位置；
#  [0-9]+ 表示匹配多个数字，[0-9] 匹配单个数字，+ 匹配一个或者多个；
#  abc$ 表示匹配字母abc并以abc结尾，$为匹配输入字符串的结束位置。
# 
#又例如：
#  常见的用户注册时用户名检查规则如下：
#  用户名应只包含大小写字母、数字、下划线和连接字符-，并设置用户名的长度3-15
#
#    开始标记      
#       |          3--15个字符的长度
#       |                 |
#       |                 |
#       |                 |
#       ^ [A-Za-z0-9_-] {3,15} $
#              |               |
#              |               |
#              |               |
#              |            结束标记
#   字母(A-Za-z)数字(0-9)
#      下划线_连字符-
# 
# !!!! 正则表达式 为单个字符逐个比较匹配
# 
# 语法介绍用代码解释
# 主要用到re.match、re.search、re.findall 等函数
# 参数格式一致(pattern,string,flags=0)
# pattern：正则表达式  string：目标匹配字符串  flag：标志位
# re.match 只匹配字符串的开始，
# 如果字符串开始不符合正则表达式，则匹配失败，函数返回 None，
# 而 re.search 匹配整个字符串，直到找到一个匹配。
  return 0

#正则表达式测试类
class RegularExpression(object):

    def __init__(self) -> None:
        pass

    # 正则表达式匹配函数，回调re模块提供的匹配函数
    def MatchReEx(self,callback,pattern,string,flags = 0):
        #该句意为：
        #在 flags 模式下使用 callback函数 按照 正则表达式：pattern 匹配某个 string
        result = callback(pattern,string,flags)
        
        #输出匹配结果
        print(result) 

        # 输出匹配结果的第n个小组成员，默认缺省参数为0
        # print(self.result.group(0)) 
        
        return result
    
    # 测试python提供的正则表达式匹配函数，写在这里用作记录并回调测试
    def CallbackTest(self):
        
        print('************测试回调不同匹配函数*************')

        # match函数：从字符串起始符号开始匹配，仅匹配一次,
        # 亦即字符串的起始符号匹配不符就会失败返回none
        result = self.MatchReEx(re.match,'www','www.runobb.com')
        
        # search函数：从字符串头部按序查找整个字符串，直到找到一个匹配结束
        # 同样仅匹配一次，可匹配字符串任意位置处的符号一次
        result = self.MatchReEx(re.search,'nob','www.runobb.com')

        # findall函数：从字符串头部按序查找整个字符串，直到找到所有匹配结束
        # 匹配多次，即可匹配字符串中所有可匹配的结果
        result = self.MatchReEx(re.findall,'ww','www.runwwobwbw.cowwm')
        
        print('*******************************************\n')
        return result
    
    # 文字字符类表达式,包括打印字符和非打印字符（回车换行等）
    def commmonRe(self):
        
        # 特殊符号本身也可当作文字字符，需加转义字符 \ 匹配本身

        print('************测试文字匹配语法*************')

        # 普通文字字符匹配的正则表达式就是本身，想匹配什么，正则表达式就写什么
        result = self.MatchReEx(re.findall,'www','www.runobb.com')
        result = self.MatchReEx(re.findall,'nobb','www.runobb.com')
        result = self.MatchReEx(re.findall,'run','www.runobb.com')

        # 当想要匹配某些格式，即字符不唯一固定的字符串时，除了后面要提的元字符，限定符
        # 普通字符可以放在[]内，表示字符集合[]内的字符均可匹配
        # [...]表示可以匹配集合中任意一个或多个字符
        # [^...]表示可以匹配除集合中字符之外的任意字符
        # ^ 出现在文字字符类表达式前表反义
        result = self.MatchReEx(re.findall,'[www]','www.runobb.com')
        result = self.MatchReEx(re.match,'[adc]','wdw.ranobb.com')
        result = self.MatchReEx(re.findall,'[adc]','wdw.ranobb.com')
        result = self.MatchReEx(re.findall,'[^wo]','www.runobb.com')
        
        # 字母 数字 之间的 - 表示范围
        # [A-Z]表示可以匹配大写字母区间内任意字符,[a-z]为小写区间
        # [0-9]表示任意数字
        result = self.MatchReEx(re.findall,'[A-Z]','wWw.RHGobB:cOm')
        result = self.MatchReEx(re.findall,'[a-z]','第abc章.RHGobb:com')
        result = self.MatchReEx(re.findall,'[0-9]','第123章.16回')
        
        # 一些特殊字符如^,$,?等在正则表达式中有特殊用途，如当作元字符，限定符
        # 但是这些字符本身也可当作文本，需要匹配这些字符本身时需要转义字符 \
        # 或放入中括号当作字符集合也可匹配本身，除在中括号内起作用的字符外，如^
        result = self.MatchReEx(re.findall,'\.','第abc章.RHGobb:com')
        result = self.MatchReEx(re.findall,'[.]','第abc章.RHGobb:com')
        result = self.MatchReEx(re.findall,'\?','第abc章?RHGobb:com')
        result = self.MatchReEx(re.findall,'[^a-z]\^','第^abc章?RHGobb:com')

        print('*******************************************\n')
        return result
    
    # 元字符类表达式，包括匹配字符串位置的字符和匹配某些字符集合的字符
    def metaRe(self):
        
        print('************测试元字符语法*************')
        
        # 元字符分为以下两类：
        # 1、匹配字符串位置的字符：^ , $ , \b , \B
        # 2、匹配字符集合的字符: \w , \W , \s , \S , \d , \D , . ,
        
        # ^ 匹配字符串起始位置，写在正则表达式开头，表示匹配需要从字符串开头匹配
        result = self.MatchReEx(re.findall,'^ab','abc章.RHGabb:abcom')

        # $ 匹配字符串结束位置，写在正则表达式结尾，表示匹配需要是字符串的尾部
        result = self.MatchReEx(re.findall,'ab$','abc章.RHGabb:comab')
        
        # \b 匹配一个单词边界位置，写在需要匹配的单词前或后，以匹配前后边界
        # 这种边界位置包括 空格 ，标点符号 ，换行等构成的。
        # 注意。\b本身在字符串中有退格的含义，python中字符串'\b'会自动转换
        # 为退格，来不及被正则表达式函数处理识别，故使用\b需要加转义字符\
        # \B 为匹配不是单词边界的位置，不需要加转义字符即可使用。
        result = self.MatchReEx(re.findall,'\\bart\\b','asd,art\nzde')
        result = self.MatchReEx(re.findall,'\Bart\B','asdartz,art.de')
        
        # . 匹配除换行符之外的字符,等价[^\r\n];
        # 注意不加中括号，加括号的[.]意为匹配句号字符,等同\.，为文字类匹配
        result = self.MatchReEx(re.findall,'.','第abc章.RHGobb:com')
    
        #[\s\S]匹配所有字符，\s是所有空白符，包括换行，\S为所有非空白符，不包括换行
        result = self.MatchReEx(re.findall,'\s\S','第 abc章.RH G obb:com') 
        result = self.MatchReEx(re.findall,'[\s\S]','asd,art\nzde')
        
        # \w 匹配单词字符，包括字母汉字数字下划线，不包括连字符-，
        # \W 匹配任意的非单词字符
        result = self.MatchReEx(re.findall,'\w','第abc.RH,156_Go-bb:com') 
        result = self.MatchReEx(re.findall,'\W','第abc.RH,156_Go-bb:com') 

        # \d 匹配数字字符
        # \D 匹配任意的非数字字符
        result = self.MatchReEx(re.findall,'\D','第abc.RH,156_Go-bb:com') 
        result = self.MatchReEx(re.findall,'\d','第abc.RH,156_Go-bb:com')

        print('**************************************')
        return result
    
    # 限定符类表达式，对限定符前的表达式做出限定的符号
    def qualifierRe(self):
        print('************测试限定符语法*************')

        # 限定符： 用来限定 限定符前的 子表达式的 匹配次数

        # 例如：
        # {n}  表示前面的子表达式重复n次
        # {n,} 表示前面的子表达式重复至少n次
        # {n,m} 表示前面的子表达式重复至少n次，最多m次
        # * 表示前面的子表达式重复至少0次,等同{0,}
        # + 表示前面的子表达式重复至少1次,等同{1,}
        # ? 表示前面的子表达式重复0次或1次,等同{0,1}
        # 在上述限定符之后再加一个 ? ，表懒惰限定，在限定规则下尽可能匹配最少次数
        # 表明不加 懒惰限定符时 默认为 贪婪限定 模式，单次匹配会在规则内尽可能多的匹配
        # 如 ww{1，3}去匹配 wwwwwwbwww 会分成 wwww 和 ww 和 www
        # 而 ww{1，3}?去匹配 wwwwwwbwww 会分成 ww 和 ww 和 ww 和 ww

        # “前面的子表达式” 为 限定符 前的 一个字符或集合
        # “匹配次数” 是单次匹配时逐个字符匹配成功的次数
        # 不是匹配字符串时一共找到多少个匹配结果

        # 例如：
        # www* 表示 匹配 * 前面的 子表达式‘w’ 至少0次,等同www{0,}
        # 匹配时，前两个ww不受限定必须出现，
        # 第三个w接受限定，可以没有，也可以有，
        # 所以可以匹配成功的字符串应为包含“ ‘ww’，‘www’，‘wwww’。。。”
        # www+ 表示 匹配 + 前面的 子表达式‘w’ 至少1次,等同www{1,}
        # 匹配时，前ww必须出现，w必须出现一次以上，所以可以匹配成功的
        # 字符串应为包含“ ‘www’，‘wwww’，‘wwwww’。。。”
        # www? 表示匹配前面的子表达式0次或1次,等同{0,1}
        # 匹配时，前ww必须出现，w出现0次或1次，所以可以匹配成功的
        # 字符串应为包含“ ‘ww’，‘www’ ”两种的

        # * 表示匹配前面的子表达式至少0次
        result = self.MatchReEx(re.findall,'www*','w+ww+www+wwww')

        # + 表示匹配前面的子表达式至少1次
        result = self.MatchReEx(re.findall,'www+','w+ww+www+wwww')

        # ? 匹配前面的子表达式0次或1次
        result = self.MatchReEx(re.findall,'www?','w+ww+www+wwww')

        # {n} 匹配前面的子表达式n次
        result = self.MatchReEx(re.findall,'w{3}','w+ww+www+wwwwww')

        # 在上述限定符之后再加一个 ? ，表懒惰限定
        result = self.MatchReEx(re.findall,'a.*?b','aabab')
        result = self.MatchReEx(re.findall,'ww{1,3}','wwwwwwbwww')
        result = self.MatchReEx(re.findall,'ww{1,3}?','wwwwwwbwww')

        print('*******************************************\n')
        return result

    #正则表达式测试
    def doTest(self):
        print('正则表达式测试输出')
        # self.CallbackTest() # 测试回调不同匹配函数
        # self.commmonRe()  # 匹配文字字符测试
        # self.metaRe()       # 元字符测试
        self.qualifierRe()  # 限定符测试


if __name__ == '__main__':
    RegularExpression().doTest()
    RegularExpression().MatchReEx(re.findall,'www','www.runobb.com')